package chen.web.user;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;

import chen.web.DataSourceProvider;
import chen.web.ExecuteHandler;
import chen.web.Executor;
import chen.web.config.ConfigRepository;
import chen.web.config.SiteConfig;
import chen.web.email.EmailAddress;
import chen.web.email.EmailSender;
import chen.web.email.SimpleEmail;
import chen.web.util.FreeMarker;

public class LostPossswordService {
	
	private SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(DataSourceProvider.getDataSource());
	
	private AccountManager am;
	private EmailSender sender;
	public LostPossswordService(AccountManager am, EmailSender sender){
		this.am = am;
		this.sender = sender;
	}
	
	private static final String SQL_86 = "insert into web_account_reset(reset_code, acc_id, reset_date, reset_used) values(?,?,?,?)";
	/**
	 * 发送密码重置码给用户
	 * @param password
	 */
	public void sendResetCode(Account account){
		SiteConfig siteConfig = ConfigRepository.instance().get(SiteConfig.class);
		String code = randomCode();
		simpleJdbcTemplate.update(SQL_86, code, account.getId(), new Date(), false);
		//准备渲染模板的数据
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("nickname", account.getNickname());
		data.put("code", code);	
		//渲染模板
		String html = FreeMarker.process("reset_password.flt", data);
		SimpleEmail email = new SimpleEmail();
		email.setHtml(html);
		email.setSubject(account.getNickname() + "，请通过这封邮件找回您在" + siteConfig.getSiteName() + "的账号密码");
		email.setTo(new EmailAddress(account.getEmail()));
		sender.send(email);
	}
	
	private static final String SQL_87 = "select * from web_account_reset where reset_code = ?";
	private static final String SQL_88 = "update web_account_reset set reset_used = true where reset_code = ?";
	/**
	 * 重置密码，如果code通过验证将重置密码,并且code会失效。
	 * @param code
	 * @param password
	 */
	public void resetPassword(String code, final String password){
		Map<String,Object> row = simpleJdbcTemplate.queryForMap(SQL_87, code);
		Date date = (java.sql.Timestamp)row.get("reset_date");
		boolean used = (Boolean)row.get("reset_used");
		int accountId = (Integer)row.get("acc_id");
		String _code = (String)row.get("reset_code");
		
		if(used){
			throw new RuntimeException("已经使用过了");
		}
		if(System.currentTimeMillis() - date.getTime() > 3*24*3600*1000){
			throw new RuntimeException("已经过期");
		}
		if(!_code.equals(code)){
			throw new RuntimeException("验证码错误");
		}
		final Account acc = am.getAccount(accountId);
		
		Executor.execute(new ExecuteHandler<Object>(){
			@Override
			public Object handle() {
				// TODO Auto-generated method stub
				am.changePassword(acc, password);
				return null;
			}
			
		});
		
		simpleJdbcTemplate.update(SQL_88, code);
	}
	
	private String randomCode(){
		String uuid = UUID.randomUUID().toString();
		MessageDigest md = null;
		
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		byte[] digest = md.digest(uuid.getBytes());
		StringBuilder sb = new StringBuilder(32);
		for(int i=0; i<digest.length; i++){
			sb.append(Integer.toHexString((0x000000ff & digest[i]) | 0xffffff00).substring(6));
		}
		return sb.toString();
	}
}
